/**
 * File TimerCyclicBehaviour.java created by Pablo Díaz Fernández
 * on 27/10/2011 for the project supply-chain-simulator
 */
package org.lsk.pfc.scsim.model.behaviour;

import java.util.List;

import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;

import org.apache.log4j.Logger;
import org.lsk.pfc.scsim.model.agent.TimerAgent;
import org.lsk.pfc.scsim.model.messages.MessageFactory;

/**
 * Cyclic behabiour that is run by the timer agent. Takes care of agent
 * syndication and synchronization.
 * 
 * @author Pablo Díaz Fernández
 * 
 */
public final class TimerCyclicBehaviour extends CyclicBehaviour {

	/**
	 * Serial version ID.
	 */
	private static final long serialVersionUID = -7138552193301971471L;

	/**
	 * Logger for the class.
	 */
	private static final Logger LOGGER = Logger
	        .getLogger(TimerCyclicBehaviour.class);

	/**
	 * TimerAgent that runs the behaviour.
	 */
	private static TimerAgent agent;

	/**
	 * @see jade.core.behaviours.Behaviour#action()
	 */
	@Override
	public void action() {
		agent = (TimerAgent) this.myAgent;

		ACLMessage message = null;
		do {
			message = agent.blockingReceive();
		} while (message == null);

		if (MessageFactory.isSyndicationReq(message)) {
			syndication(message);
		} else if (MessageFactory.isEOT(message)) {
			eot(message);
		}

		// When all active agents have sent EOT, send new tick
		List<AID> agents = agent.readyForNextTick();
		if (agents != null) {

			LOGGER.debug("[Timer] Tick " + agent.getCurrentTick());

			newTick(agents);
		}
	}

	/**
	 * Sends a notification to all sindicated agents of a new tick.
	 * 
	 * @param agents
	 *            {@link List} of {@link AID} with the name of the agents to
	 *            notify.
	 */
	private void newTick(final List<AID> agents) {
		agent.incTick();
		long newTick = agent.getCurrentTick();
		for (AID targetAID : agents) {
			agent.send(MessageFactory.getNewTickMsg(targetAID, agent.getAID(),
			        newTick));
		}
	}

	/**
	 * Processes an End-Of-Tick message.
	 * 
	 * @param message
	 *            {@link ACLMessage} with the information.
	 */
	private void eot(final ACLMessage message) {
		String agentName = message.getSender().getName();
		agent.setEOT(agentName);

		LOGGER.debug("[Timer] EOT from " + agentName);
	}

	/**
	 * Processes a request for syndication.
	 * 
	 * @param message
	 *            {@link ACLMessage} with the request.
	 */
	private void syndication(final ACLMessage message) {
		String agentName = message.getSender().getName();

		LOGGER.debug("[Timer] Synd from " + agentName);

		agent.addSyndication(agentName, message.getSender());
		agent.send(MessageFactory.getConfirmSynMsg(agentName));

		LOGGER.debug("[Timer] ACK to " + agentName);

	}
}
